package org.sam.swing.table.tools;

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ItemEvent;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.RowFilter;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.jdesktop.swingx.JXTable;
import org.jdesktop.swingx.sort.RowFilters;
import org.sam.swing.JSComboBox;
import org.sam.swing.JSToolBar;
import org.sam.swing.resource.ResourceLoader;
import org.sam.swing.table.JSTableColumnModel;
import org.sam.swing.table.model.FilterObject;
import org.sam.swing.table.model.FilterOperation;

/**
 * 扩展的过滤栏 主要增加字段选择列表：全部 + 可见字段列表 +号按钮，多条件窗口 apply按钮，接受条件
 * 
 * @author sam
 *
 */
public class JSTableFilterBar extends JSToolBar implements FilterOperation {

	private static final long serialVersionUID = 1594690163014862566L;

	/**
	 * 清空按钮
	 */
	protected JButton btnClear;

	/**
	 * 筛选按钮
	 */
	protected JButton btnApply;

	/**
	 * 用户自定义的条件集合
	 */
	protected Map<Integer, Pair<String, String>> pattens = new LinkedHashMap<>();

	/**
	 * 当前操作的表格控件
	 */
	protected JXTable table;

	/**
	 * 当前的tablemodel
	 */
	protected TableModel tableModel;

	/**
	 * 当前的列model
	 */
	protected TableColumnModel colModel;

	/**
	 * 输入条件
	 */
	protected JTextField txtPatten;

	/**
	 * 条件下来列表框
	 */
	protected JComboBox<String> ddlbCondition;

	/**
	 * 当前操作的表格控件
	 * 
	 * @return
	 */
	public JXTable getTable() {
		return table;
	}

	/**
	 * 当前操作的表格控件
	 * 
	 * @param table
	 */
	public void setTable(JXTable table) {
		this.table = table;
	}

	/**
	 * 当前的tablemodel
	 * 
	 * @return
	 */
	public TableModel getTableModel() {
		return tableModel;
	}

	/**
	 * 当前的tablemodel
	 * 
	 * @param tableModel
	 */
	public void setTableModel(TableModel tableModel) {
		this.tableModel = tableModel;
	}

	/**
	 * 当前的列模型
	 * 
	 * @return
	 */
	public TableColumnModel getColModel() {
		return colModel;
	}

	/**
	 * 当前的列模型
	 * 
	 * @param colModel
	 */
	public void setColModel(TableColumnModel colModel) {
		this.colModel = colModel;
	}

	/**
	 * 是否加入生成过滤条件设置按钮
	 */
	private boolean configDialog = true;

	/**
	 * 加入生成过滤条件设置按钮
	 * 
	 * @return
	 */
	public boolean isConfigDialog() {
		return configDialog;
	}

	/**
	 * 加入生成过滤条件设置按钮
	 * 
	 * @param configDialog
	 */
	public void setConfigDialog(boolean configDialog) {
		this.configDialog = configDialog;
	}

	/**
	 * 字段列表
	 */
	protected JSComboBox<Integer, String> columsList;

	/**
	 * 扩展的过滤栏 主要增加字段选择列表：全部 + 可见字段列表 +号按钮，多条件窗口 apply按钮，接受条件
	 * 
	 * @param table
	 */
	public JSTableFilterBar(JXTable table) {
		this(table, null, null);
	}

	public JSTableFilterBar(JXTable table, TableModel tableModel, TableColumnModel colModel) {
		super();
		this.setTable(table);
		this.setTableModel(tableModel);
		this.setColModel(colModel);
		this.initComponents();
		this.initEvents();
	}

	/**
	 * 初始化控件显示
	 */
	protected void initComponents() {
		this.setLayout(new FlowLayout(FlowLayout.RIGHT, 0, 0));

		// 初始化条件下来列表对象
		ddlbCondition = new JComboBox<>(new String[] { CONTAINS, EQUAL, NOTEQUAL, MORETHAN, LESSTHAN, IN });

		btnClear = this.buildButton(ResourceLoader.IMAGE_DELETE, "", "清空全部过滤条件", e -> {
			pattens.clear();
			try {
				setRowFilters();
			} catch (Exception e1) {
				e1.printStackTrace();
			}
			txtPatten.setText("");
		});

		btnApply = this.buildButton(ResourceLoader.IMAGE_PLAY, "过滤", "执行数据过滤操作", e -> {
			String patten = txtPatten.getText();
			Integer selectedValue = columsList.getSelectedValue();
			if (!StringUtils.isEmpty(patten)) {
				this.pattens.put(selectedValue, Pair.of(ddlbCondition.getSelectedItem().toString(), patten));
			} else {
				if (this.pattens.containsKey(selectedValue)) {
					this.pattens.remove(selectedValue);
				}
			}
			try {
				setRowFilters();
			} catch (Exception e1) {
				JOptionPane.showMessageDialog(null, e1.getMessage());
			}
		});

		txtPatten = new JTextField();
		txtPatten.setPreferredSize(new Dimension(175, 25));

		/**
		 * 初始化类列表
		 */
		Map<Integer, String> colNames = ((JSTableColumnModel) this.colModel).getColumnNamesMapWithIndex();
		columsList = new JSComboBox<>(colNames);

		// 条件对话框
		if (this.isConfigDialog()) {
			JButton btnFilter = this.buildButton(ResourceLoader.IMAGE_FIND, "条件", "设置过滤条件", e -> {

				Pair<String, List<FilterObject>> result = JDialogFilter.showFilterDialogWidthAction(this.getTable(),
						this.getFilterObjects());

				if (JDialogFilter.OK.equals(result.getKey())) {
					try {
						this.setFilterObjects(result.getValue());
						setRowFilters(result.getValue());
					} catch (Exception e1) {
						JOptionPane.showMessageDialog(null, e1.getMessage());
					}
				}
			});
			this.add(btnFilter);
		}

		this.add(btnClear);
		this.add(columsList);
		this.add(ddlbCondition);
		this.add(txtPatten);
		this.add(btnApply);

	}

	/**
	 * 给控件绑定事件
	 */
	protected void initEvents() {

		txtPatten.addActionListener(e -> {
			btnApply.doClick();
		});

		// 下拉列表跳转
		// 一次下拉操作会出发2次这个事件
		columsList.addItemListener(e -> {

			if (e.getStateChange() == ItemEvent.DESELECTED) {

				// 取消选中
				int index = ((DefaultComboBoxModel<?>) columsList.getModel()).getIndexOf(e.getItem());
				Integer valueAt = columsList.getValueAt(index);
				// 如果用户输入值了，则直接插入
				if (txtPatten.getText().length() > 0) {
					this.pattens.put(valueAt, Pair.of(ddlbCondition.getSelectedItem().toString(), txtPatten.getText()));
				} else {
					// 如果用户删除了值，则删除条件
					if (this.pattens.containsKey(index)) {
						this.pattens.remove(valueAt);
					}
				}

			} else if (e.getStateChange() == ItemEvent.SELECTED) {

				// 选中状态
				Integer index = ((DefaultComboBoxModel<?>) columsList.getModel()).getIndexOf(e.getItem());
				Integer selectedValue = columsList.getValueAt(index);
				if (pattens.containsKey(selectedValue)) {
					Pair<String, String> pair = pattens.get(selectedValue);
					txtPatten.setText(pair.getValue());
					ddlbCondition.setSelectedItem(pair.getKey());
				} else {
					txtPatten.setText("");
				}
			} else {
				System.out.println("unknow type");
			}
		});
	}

	/**
	 * 生成filters对象
	 */
	protected void setRowFilters() throws Exception {
		if (this.pattens == null && this.pattens.isEmpty()) {
			if (this.table != null) {
				this.table.setRowFilter(null);
			}
		} else {

			List<RowFilter<Object, Object>> filters = new LinkedList<>();

			// 拼接RowFilter给table过滤用
			for (Entry<Integer, Pair<String, String>> entry : this.pattens.entrySet()) {
				// key : contdition
				// value : condition-value
				Pair<String, String> pair = entry.getValue();
				if (!StringUtils.isEmpty(pair.getValue())) {
					if (null == entry.getKey()) {
						filters.add(RowFilters.regexFilter(pair.getValue()));
					} else {
						Class<?> cls = tableModel.getColumnClass(entry.getKey());
						filters.add(
								FilterOperation.convertRowFilter(cls, pair.getKey(), entry.getKey(), pair.getValue()));
					}
				}
			}

			if (this.table != null) {
				table.setRowFilter(RowFilter.andFilter(filters));
			}
		}
	}

	/**
	 * 生成filters对象
	 * 
	 * @param filterObjects
	 * @throws Exception
	 */
	protected void setRowFilters(List<FilterObject> filterObjects) throws Exception {
		if (this.pattens == null && this.pattens.isEmpty()) {
			if (this.table != null) {
				this.table.setRowFilter(null);
			}
		} else {

			List<RowFilter<Object, Object>> filters = new LinkedList<>();

			for (FilterObject filter : filterObjects) {
				int colIndex = colModel.getColumnIndex(filter.getFiled());
				// 拼接RowFilter给table过滤用
				// key : contdition
				// value : condition-value
				if (!StringUtils.isEmpty(filter.getPatternValue())) {
					if (null == filter.getCondition()) {
						filters.add(RowFilters.regexFilter(filter.getPatternValue()));
					} else {
						Class<?> cls = tableModel.getColumnClass(colIndex);
						filters.add(FilterOperation.convertRowFilter(cls, filter.getCondition(), colIndex,
								filter.getPatternValue()));
					}
				}
			}

			if (this.table != null) {
				table.setRowFilter(RowFilter.andFilter(filters));
			}
		}
	}

	/**
	 * {@inheritDoc} 按照and拼接返回给调用者
	 */
	@Override
	public List<FilterObject> getFilterObjects() {
		List<FilterObject> result = new ArrayList<>();

		int i = 0;
		for (Entry<Integer, Pair<String, String>> entry : this.pattens.entrySet()) {
			FilterObject filter = new FilterObject();
			filter.setCondition(entry.getValue().getKey());
			filter.setConnectCondition(AND);
			filter.setFiled(tableModel.getColumnName(entry.getKey()));
			filter.setPatternValue(entry.getValue().getValue());
			if (i == 0) {
				filter.setConnectCondition(EMPTY);
			}
			i++;
			result.add(filter);
		}
		return result;
	}

	/**
	 * {@inheritDoc} 重新装配拼接条件对象
	 */
	@Override
	public void setFilterObjects(List<FilterObject> fitlers) {
		this.pattens.clear();
		this.txtPatten.setText(EMPTY);

		if (fitlers == null || fitlers.isEmpty())
			return;

		for (FilterObject filter : fitlers) {
			int index = colModel.getColumnIndex(filter.getFiled());
			this.pattens.put(index, Pair.of(filter.getCondition(), filter.getPatternValue()));
		}

		FilterObject filterObject = fitlers.get(0);
		int index = ((JSTableColumnModel) this.getColModel()).getDataIdentifierIndex(filterObject.getFiled());
		if (index >= 0 && index < this.columsList.getItemCount()) {
			this.columsList.setSelectedIndex(index);
		}
	}
}
